<!--
 * @Descripttion: 权限设置
 * @LastEditors: xzh
 * @LastEditTime: 2023-09-04 20:20:47
-->
<template>
  <DileDrawer
    v-model="rolePowerForm.visible"
    :loading="rolePowerForm.loading"
    size="80%"
    @close="rolePowerForm.visible = false"
    @sure="hanldeSure"
  >
    <template #header>
      <span>{{ $t(`table.btnArr.powerSet`) }}</span>
    </template>
    <template #default>
      <div class="powerSet-container">
        <!-- 角色信息 -->
        <el-card>
          <el-descriptions :column="1">
            <el-descriptions-item
              :label="$t('page.organizeManageArr.roleArr.roleName') + ':'"
            >
              {{ rolePowerForm.roleInfo.name }}
            </el-descriptions-item>
            <el-descriptions-item
              :label="$t('page.organizeManageArr.roleArr.relPeople') + ':'"
              >{{ rolePowerForm.roleInfo.relPeopleNames }}</el-descriptions-item
            >
          </el-descriptions>
        </el-card>
        <!-- 角色菜单&&工具栏权限设置 -->
        <el-card>
          <DileTable ref="dileTableRef">
            <template #preColumn>
              <vxe-column
                v-for="deepIndex in rolePowerForm.menuDeep"
                :key="deepIndex"
                :field="`menuDeep_${deepIndex}`"
                width="150"
              >
                <template #header>
                  <div class="powerSet-columnHeader">
                    <el-checkbox
                      v-if="deepIndex == 1"
                      v-model="rolePowerForm.checkAll"
                      @change="hanldeMoudleCheckChange($event, {}, 0)"
                    />
                    <span>{{
                      $t(`page.organizeManageArr.roleArr.deepArr.${deepIndex}`)
                    }}</span>
                  </div>
                </template>
                <template #default="{ row }">
                  <el-checkbox
                    v-if="row[`menuDeep_${deepIndex}`]"
                    :disabled="
                      Dile_Constants.fixModuleArr.includes(
                        row[`menuDeepName_${deepIndex}`]
                      )
                    "
                    :label="$t(row[`menuDeep_${deepIndex}`])"
                    v-model="row[`menuDeephasPower_${deepIndex}`]"
                    @change="hanldeMoudleCheckChange($event, row, deepIndex)"
                  />
                </template>
              </vxe-column>
              <vxe-column :title="$t('common.function')">
                <template #default="{ row }">
                  <el-checkbox-group
                    v-model="row.toolBtnPowerArr"
                    class="powerSet-toolsBtn"
                  >
                    <el-checkbox
                      v-for="(toolBtn, index) in row.toolBtnArr"
                      :key="index"
                      :label="toolBtn.code"
                      >{{ $t(toolBtn.label) }}</el-checkbox
                    >
                  </el-checkbox-group>
                </template>
              </vxe-column>
            </template>
          </DileTable>
        </el-card>
      </div>
    </template>
  </DileDrawer>
</template>

<script setup lang="ts">
import { ref, reactive, provide, toRefs, nextTick } from "vue";
import { object_Inf } from "@/utils/typings/index.type";
import { useI18n } from "vue-i18n";
import { ElNotification } from "element-plus";
import { propsParam_Inf } from "@/components/dile-table/index.type";
import DileTable from "@/components/dile-table/index.vue";
import DileDrawer from "@/components/dile-drawer/index.vue";
import Dile_Constants from "@/utils/constants/app";
import DilePower_Constants from "@/utils/constants/modulePower";
import DileRouter_Constants from "@/utils/constants/router";
import Dile_Methods from "@/utils/methods";
import Dile_APi from "@/api";

let { t } = useI18n();
/**
 * @Author: xzh
 * @Descripttion: 角色表单参数
 * @Param:
 */
let rolePowerForm = reactive<object_Inf>({
  visible: false,
  loading: false,
  checkAll: false,
  powerSetInfo: {
    id: 0,
  },
  roleInfo: {},
  tableArr: [],
  menuDeep: 0,
});

/**
 * @Author: xzh
 * @Descripttion: 初始化
 * @Param:
 */
let init = async (roleInfo: object_Inf) => {
  rolePowerForm.visible = true;
  await nextTick();
  try {
    Object.assign(rolePowerForm, {
      loading: true,
      roleInfo,
      tableArr: [],
      menuDeep: 0,
    });
    //加载权限设置信息
    await initPowerSetInfo();
    //加载权限列表
    initPowerTable();
  } finally {
    rolePowerForm.loading = false;
  }
};
/**
 * @Author: xzh
 * @Descripttion: 加载权限设置信息
 * @Param:
 */
let initPowerSetInfo = async () => {
  let { id: roleId } = rolePowerForm.roleInfo;
  //加载角色对应权限设置
  let { id, powerSetJson } = await Dile_APi.getRolePowerSetInfo(roleId);
  Object.assign(rolePowerForm.powerSetInfo, {
    id,
    powerSetJson: JSON.parse(powerSetJson || "{}"),
  });
};
/**
 * @Author: xzh
 * @Descripttion:加载权限列表
 * @Param:
 */
let initPowerTable = () => {
  //格式化路由菜单成树结构
  let { treeData: routerArr } = Dile_Methods.formatToTree(
      DileRouter_Constants.routerArr,
      {
        id: "guid",
        parentId: "parentGuid",
        children: "children",
      }
    ),
    tableArr: Array<object_Inf> = [];

  routerArr.forEach((router: object_Inf) => {
    let deepIndex = 1,
      row: object_Inf = {};
    //格式化路由菜单权限
    formatRouterTreePower({
      router,
      deepIndex,
      row,
      tableArr,
    });
  });
  propsParam.tableData = tableArr;
};

/**
 * @Author: xzh
 * @Descripttion:格式化路由菜单权限
 * @Param:
 * @param {*} param
 */
let formatRouterTreePower = (param: object_Inf) => {
  let { router, deepIndex, row } = param,
    { liDataName: name, liName: title, children } = router || {},
    { powerSetInfo } = rolePowerForm;
  //获取模块对应已有配置
  let { module: cacheName, toolBtnPowerArr } =
    ((powerSetInfo?.powerSetJson || {}).modulePowerArr || []).find(
      (x: object_Inf) => x.module == name
    ) || {};
  // 层级自增
  param.deepIndex++;
  //记录最深层级
  if (deepIndex > rolePowerForm.menuDeep) {
    rolePowerForm.menuDeep = deepIndex;
  }
  if (children?.length > 0) {
    //层级菜单->填充层级对象名称
    children.forEach((_router: object_Inf) => {
      //格式化路由菜单权限
      formatRouterTreePower({
        ...param,
        row: {
          ...row,
          [`menuDeep_${deepIndex}`]: title,
          [`menuDeepName_${deepIndex}`]: name,
          [`menuDeephasPower_${deepIndex}`]:
            //固定模块默认勾选
            Dile_Constants.fixModuleArr.includes(name) ? true : !!cacheName,
        },
        router: _router,
      });
    });
  } else {
    //功能菜单-填充对应模块按钮
    let toolBtnArr = (DilePower_Constants[`${name}Tools`] || []).map(
      (x: object_Inf) => ({
        label: x.label,
        code: x.code,
      })
    );
    let moduleRow = {
      ...JSON.parse(JSON.stringify(row)),
      id: Dile_Methods.newGuid(),
      [`menuDeep_${deepIndex}`]: title,
      [`menuDeepName_${deepIndex}`]: name,
      [`menuDeephasPower_${deepIndex}`]:
        //固定模块默认勾选
        Dile_Constants.fixModuleArr.includes(name) ? true : !!cacheName,
      module: name,
      toolBtnArr,
      toolBtnPowerArr: toolBtnPowerArr || [],
    };
    param.tableArr.push(moduleRow);
  }
};
/**
 * @Author: xzh
 * @Descripttion: 表格合并方法
 * @Param:
 * @param {*} row
 * @param {*} _rowIndex
 * @param {*} column
 * @param {*} visibleData
 */
let hanldeSpanMethod = ({
  row,
  _rowIndex,
  column,
  visibleData,
}: object_Inf) => {
  let fieldkey = "menuDeep_";
  const cellValue = row[column.field];
  if (cellValue && column.field.includes(fieldkey)) {
    const prevRow = visibleData[_rowIndex - 1];
    let nextRow = visibleData[_rowIndex + 1];
    if (prevRow && prevRow[column.field] === cellValue) {
      return { rowspan: 0, colspan: 0 };
    } else {
      let countRowspan = 1;
      while (nextRow && nextRow[column.field] === cellValue) {
        nextRow = visibleData[++countRowspan + _rowIndex];
      }
      if (countRowspan > 1) {
        return { rowspan: countRowspan, colspan: 1 };
      }
    }
  }
};

/**
 * @Author: xzh
 * @Descripttion: 模块菜单勾选事件
 * @Param:
 * @param {*} value
 */
let hanldeMoudleCheckChange = (
  value: any,
  row: object_Inf,
  deepIndex: number
) => {
  let guidKey = `menuDeepName_${deepIndex}`,
    { tableData } = propsParam;
  //获取当前模块所有子模块
  let childrenModule: Array<object_Inf> =
    deepIndex > 0
      ? (tableData || []).filter((x: object_Inf) => x[guidKey] == row[guidKey])
      : tableData || [];
  childrenModule.forEach((childModule: object_Inf) => {
    //全选/取消全部->修改子模块权限
    Object.keys(childModule)
      .filter(
        (x: string) =>
          !!x.includes("menuDeepName_") &&
          Number(x?.replace("menuDeepName_", "")) >= deepIndex
      )
      .filter(
        (deepName) =>
          !Dile_Constants.fixModuleArr.includes(childModule[deepName])
      )
      .map((x) => Number(x?.replace("menuDeepName_", "")))
      .forEach(
        (_deepIndex) => (childModule[`menuDeephasPower_${_deepIndex}`] = value)
      );

    //全选/取消全部->修改按钮权限
    childModule.toolBtnPowerArr = !!value
      ? childModule.toolBtnArr.map((x: object_Inf) => x.code)
      : [];
  });

  //勾选时->勾选父级状态
  if (!!value) {
    //获取父级deepGuid
    Object.keys(row)
      .filter(
        (x: string) =>
          !!x.includes("menuDeepName_") &&
          Number(x?.replace("menuDeepName_", "")) < deepIndex
      )
      .filter(
        (deepName) => !Dile_Constants.fixModuleArr.includes(row[deepName])
      )
      .forEach((deepGuid: string) => {
        let _deepIndex = Number(deepGuid?.replace("menuDeepName_", ""));
        tableData
          ?.filter((x: object_Inf) => x[deepGuid] == row[deepGuid])
          .forEach(
            (parentMoudle: object_Inf) =>
              (parentMoudle[`menuDeephasPower_${_deepIndex}`] = true)
          );
      });
  }
};

/**
 * @Author: xzh
 * @Descripttion: 保存事件
 * @Param:
 */
let hanldeSure = async () => {
  let { loading, powerSetInfo, roleInfo, visible } = toRefs(rolePowerForm);
  if (!!loading.value) {
    return false;
  }
  try {
    loading.value = true;
    let { tableData } = propsParam,
      { id } = powerSetInfo.value,
      modulePowerArr: Array<object_Inf> = [];
    //格式化配置权限设置
    tableData?.forEach((row: object_Inf) => {
      Object.keys(row)
        //获取有权限的模块
        .filter(
          (key: string) => !!key.includes("menuDeephasPower_") && !!row[key]
        )
        .forEach((deepPowerKey) => {
          //获取模块层级
          let deepIndex = Number(
              deepPowerKey?.replace("menuDeephasPower_", "")
            ),
            moduleGuid = row[`menuDeepName_${deepIndex}`];

          //模块对应权限
          let modulePower = {
            module: moduleGuid,
            //模块对象工具栏按钮权限
            toolBtnPowerArr:
              tableData?.find((x) => x.module == moduleGuid)?.toolBtnPowerArr ||
              [],
          };

          let index = modulePowerArr.findIndex((x) => x.module == moduleGuid);
          index > -1
            ? (modulePowerArr[index] = modulePower)
            : modulePowerArr.push(modulePower);
        });
    });
    await Dile_APi.saveRolePowerSet({
      id,
      roleId: roleInfo.value.id,
      powerSetJson: JSON.stringify({
        modulePowerArr,
      }),
    });
    //提示成功
    ElNotification({
      message: t("common.message.OperationSuccess"),
      type: "success",
    });
    //关闭弹框
    visible.value = false;
  } finally {
    loading.value = false;
  }
};
/**
 * @Author: xzh
 * @Descripttion: 表格参数
 * @Param:
 */
let propsParam = reactive<propsParam_Inf>({
  notNeedNumber: true,
  loading: false,
  tableData: [],
  scrollY: {
    enabled: false,
  },
  spanMethod: hanldeSpanMethod,
});
provide("propsParam", propsParam);

defineExpose({
  init,
});
</script>
<style lang="scss" scoped>
.powerSet-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  gap: 1rem;
  > .el-card {
    &:first-child {
      flex: 5rem 0 0;
    }
    &:last-child {
      flex: 1;
      height: 0;
      :deep(.el-card__body) {
        height: 0;
        .powerSet-columnHeader {
          display: flex;
          align-items: center;
          gap: 0.5rem;
        }

        .powerSet-toolsBtn {
          display: flex;
          flex-direction: row;
          flex-wrap: wrap;
        }
      }
    }
  }
}
</style>
